package com.greatwqs.wmall.user.provider.manager.impl;

import com.greatwqs.wmall.common.module.exception.AppException;
import com.greatwqs.wmall.common.module.exception.ErrorCode;
import com.greatwqs.wmall.common.provider.cache.CacheNames;
import com.greatwqs.wmall.user.provider.manager.UserLoginManager;
import com.greatwqs.wmall.user.provider.mapper.UserLoginMapper;
import com.greatwqs.wmall.user.provider.model.po.UserLogin;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.UUID;

/**
 * User 通用功能实现
 *
 * @author wang-qingsong
 */
@Slf4j
@Component
public class UserLoginManagerImpl implements UserLoginManager {

    /**
     * SESSION 过期时间
     */
    private static final int SESSION_TIMEOUT_IN_MINUTES = 120;

    @Autowired
    private UserLoginMapper userLoginMapper;

    @Override
    @Transactional
    public UserLogin createLogin(Long userId) {
        UserLogin login = new UserLogin();
        login.setSeq(null);
        login.setUserId(userId);
        login.setLoginToken(UUID.randomUUID().toString());
        login.setExpireTime(new Date(System.currentTimeMillis() + SESSION_TIMEOUT_IN_MINUTES * 1000L * 60));
        login.setValid(true);
        login.setCreateTime(new Date());
        login.setUpdateTime(new Date());
        userLoginMapper.insert(login);
        return login;
    }

    @Override
    @Cacheable(cacheNames = CacheNames.USER_LOGIN, key = "#loginToken", sync = true)
    public UserLogin getValidatedPoNotNull(String loginToken) {
        if (StringUtils.isEmpty(loginToken)) {
            log.warn("getValidatedPoNotNull, NULL loginToken!");
            throw new AppException(ErrorCode.LOGIN_AUTH_NOT_FOUND_OR_EXPIRED);
        }
        UserLogin po = userLoginMapper.selectByLoginToken(loginToken);
        if (po == null) {
            log.warn("getValidatedPoNotNull, po null, loginToken: {}", loginToken);
            throw new AppException(ErrorCode.LOGIN_AUTH_NOT_FOUND_OR_EXPIRED);
        }
        if (!po.getValid()) {
            log.warn("getValidatedPoNotNull, po not valid, loginToken: {}", loginToken);
            throw new AppException(ErrorCode.LOGIN_AUTH_NOT_FOUND_OR_EXPIRED);
        }
        if (po.getExpireTime().getTime() < System.currentTimeMillis()) {
            log.warn("getValidatedPoNotNull, token expired, loginToken: {}", loginToken);
            throw new AppException(ErrorCode.LOGIN_AUTH_NOT_FOUND_OR_EXPIRED);
        }
        return po;
    }

    @Override
    @Transactional
    @CacheEvict(cacheNames = CacheNames.USER_LOGIN, key = "#userLogin.loginToken")
    public void refresh(UserLogin userLogin) {
        UserLogin update = new UserLogin();
        final long newExpireTime = SESSION_TIMEOUT_IN_MINUTES * 60 * 1000L + System.currentTimeMillis();
        update.setExpireTime(new Date(newExpireTime));
        update.setUpdateTime(new Date());
        update.setLoginToken(userLogin.getLoginToken());
        userLoginMapper.updateExpireTimeByLoginToken(update);
    }

    @Override
    @Transactional
    @CacheEvict(cacheNames = CacheNames.USER_LOGIN, key = "#userLogin.loginToken")
    public void delete(UserLogin userLogin) {
        userLoginMapper.deleteByLoginToken(userLogin.getLoginToken());
    }
}
